﻿<%@ WebHandler Language="C#" Class="upload" %>

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;

public class upload : IHttpHandler
{
    private static readonly string FileInputName = "filedata";//表单文件域name
    private static readonly string FileSavePath = "/upload/";// 上传文件保存路径，结尾不要带/
    private static readonly string AbsoluteFileSavePath;//上传文件本地根路径
    private static readonly int MaxFileSize = 10485760;//最大文件大小10M 10*1024*1024
    private static readonly Regex Html5FileNamePattern = new Regex("filename=\"(.+?)\"", RegexOptions.Compiled);//获取用html5上传的文件名
    private static readonly Regex DangerFileName = new Regex("[.:; ]", RegexOptions.Compiled);//可能存在利用iis漏洞的文件名
    private static readonly Dictionary<string, string> AllowedExtensions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);//允许的扩展名，并按扩展名存储文件
    private static readonly List<string> DirectoryCache = new List<string>();//目录名称缓存

    private static bool enableThumbnail = true;//启用缩略图
    private static int thumbWidth = 400;//缩略图宽度
    private static int thumbHeight = 300;//缩略图高度
    private static bool isTextWatermark = true;//若启用图片水印，是否使用文字水印
    private static readonly string watermarkTextorImage = "龙疼";//水印文本或图片 HttpContext.Current.Server.MapPath("/images/watermark.png");
    private static int waterFontSize = 20;//文字水印字体大小
    private static readonly string waterFont = "黑体";//文字水印字体
    private static Color waterColor = Color.Black;//水印字体颜色
    private static FontStyle waterFontStyle = FontStyle.Bold;//字体样式

    static upload()
    {
        AllowedExtensions.Add(".txt", "file/");
        AllowedExtensions.Add(".rar", "file/");
        AllowedExtensions.Add(".zip", "file/");
        AllowedExtensions.Add(".doc", "file/");
        AllowedExtensions.Add(".docx", "file/");
        AllowedExtensions.Add(".xls", "file/");
        AllowedExtensions.Add(".xlsx", "file/");
        AllowedExtensions.Add(".ppt", "file/");
        AllowedExtensions.Add(".pptx", "file/");
        AllowedExtensions.Add(".pdf", "file/");
        AllowedExtensions.Add(".tif", "file/");
        AllowedExtensions.Add(".tiff", "file/");

        AllowedExtensions.Add(".jpg", "image/");
        AllowedExtensions.Add(".jpeg", "image/");
        AllowedExtensions.Add(".gif", "image/");
        AllowedExtensions.Add(".png", "image/");
        AllowedExtensions.Add(".bmp", "image/");

        AllowedExtensions.Add(".swf", "flash/");

        AllowedExtensions.Add(".wmv", "media/");
        AllowedExtensions.Add(".avi", "media/");
        AllowedExtensions.Add(".wma", "media/");
        AllowedExtensions.Add(".wav", "media/");
        AllowedExtensions.Add(".asf", "media/");
        AllowedExtensions.Add(".mp3", "media/");
        AllowedExtensions.Add(".mid", "media/");

        AllowedExtensions.Add(".flv", "flv/");

        AbsoluteFileSavePath = HttpContext.Current.Server.MapPath(FileSavePath);
    }

    public void ProcessRequest(HttpContext context)
    {
        ProcessUpload(context);
    }

    void ProcessUpload(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;
        string disposition = request.ServerVariables["HTTP_CONTENT_DISPOSITION"];//html5上传
        string filename;
        byte[] fileData;

        #region 取得文件名及长度
        if (!string.IsNullOrEmpty(disposition))
        {
            if (!TryGetHtml5FileName(disposition, out filename))
            {
                WriteError(response, "无数据提交");
                return;
            }
            fileData = request.BinaryRead(request.TotalBytes);
        }
        else
        {
            HttpPostedFile postedFile = request.Files[FileInputName];
            if (postedFile == null)
            {
                WriteError(response, "无数据提交");
                return;
            }
            filename = postedFile.FileName;
            fileData = new byte[postedFile.ContentLength];
            using (Stream s = postedFile.InputStream)
            {
                s.Read(fileData, 0, request.ContentLength);
            }
        }
        #endregion

        //检查文件长度及文件名、扩展名
        if (!IsValidFileLength(response, fileData.Length) ||
            !TryGetFileName(response, ref filename))
        {
            return;
        }

        string uploadFullName = GetUploadFullName(filename);
        try
        {
            string absoluteFullName = Path.Combine(AbsoluteFileSavePath, uploadFullName);//转换为本地路径
            CheckDirectoryExists(absoluteFullName);

            //上传文件
            using (FileStream fs = new FileStream(absoluteFullName, FileMode.Create, FileAccess.Write))
            {
                fs.Write(fileData, 0, fileData.Length);
                fs.Flush();
            }
            bool useWatermark = request.QueryString["watermark"] == "1";//是否加入水印
            if (enableThumbnail)
                ImageUtil.ThumbnailImage(fileData, absoluteFullName, useWatermark);//生成缩略图

            string url = FileSavePath + uploadFullName;//输出相对路径
            string immediate = request.QueryString["immediate"];//立即上传模式，xheditor处理
            if (immediate == "1")
                url = "!" + url;
            /*if (uploadFullName.Contains("file/")){
              url += "||附件:" + Path.GetFileName(uploadFullName);
              
              if (immediate != "1")
                url = "!" + url;
            }*/

            fileData = null;
            WriteMessage(response, "{'url':'" + ToJsonString(url) + "','localname':'" + ToJsonString(filename) + "','id':'1'}");
        }
        catch (Exception ex)
        {
            WriteError(response, ex.Message);
        }
    }

    /// <summary>
    /// 获取html5文件名
    /// </summary>
    /// <param name="disposition"></param>
    /// <param name="filename"></param>
    /// <returns></returns>
    bool TryGetHtml5FileName(string disposition, out string filename)
    {
        Match m = Html5FileNamePattern.Match(disposition);
        if (m != null)
        {
            filename = m.Groups[1].Value;
            if (!string.IsNullOrEmpty(filename))
            {
                return true;
            }
        }

        filename = string.Empty;
        return false;
    }

    /// <summary>
    /// 检查文件名及路径是否合法，移除文件名的路径部分
    /// </summary>
    /// <param name="response"></param>
    /// <param name="filename">原始文件名</param>
    /// <returns></returns>
    bool TryGetFileName(HttpResponse response, ref string filename)
    {
        string ext = string.Empty;
        bool isValid = false;
        try
        {
            ext = Path.GetExtension(filename);
            isValid = true;
        }
        catch { }

        if (!isValid || !AllowedExtensions.ContainsKey(ext))
        {
            WriteError(response, "上传文件扩展名" + ext + "非法");
            return false;
        }

        string name = Path.GetFileNameWithoutExtension(filename);
        if (!string.IsNullOrEmpty(name))
            name = DangerFileName.Replace(name, string.Empty);//去除可能存在漏洞的文件名
        if (string.IsNullOrEmpty(name))
            name = Guid.NewGuid().ToString("N");
        filename = name + ext;
        return true;
    }

    /// <summary>
    /// 检查文件大小
    /// </summary>
    /// <param name="response"></param>
    /// <param name="fileLength">文件大小</param>
    /// <returns></returns>
    bool IsValidFileLength(HttpResponse response, int fileLength)
    {
        if (fileLength == 0)
        {
            WriteError(response, "无数据提交");
            return false;
        }
        else if (fileLength > MaxFileSize)
        {
            WriteError(response, "文件大小超过" + MaxFileSize.ToString() + "字节");
            return false;
        }
        return true;
    }

    /// <summary>
    /// 检查目录是否存在
    /// 不存在就创建，并把名称加入缓存
    /// </summary>
    /// <param name="absolutePath"></param>
    void CheckDirectoryExists(string absolutePath)
    {
        string absoluteFullPath = Path.GetDirectoryName(absolutePath);
        if (DirectoryCache.Contains(absoluteFullPath))
            return;

        if (!Directory.Exists(absoluteFullPath))
            Directory.CreateDirectory(absoluteFullPath);
        DirectoryCache.Add(absoluteFullPath);
    }

    static Regex reFileName = new Regex("^(\\d)-", RegexOptions.Compiled);
    /// <summary>
    /// 生成文件名
    /// </summary>
    /// <param name="filename"></param>
    /// <returns></returns>
    string GetUploadFullName(string filename)
    {
        string extDir = AllowedExtensions[Path.GetExtension(filename)];//当前扩展名存储的路径
        string todayDir = DateTime.Now.ToString("yyyy/MM/dd") + "/";//按日期保存
        string fullNameWithoutRoot = string.Empty;//文件存储路径，不包括根路径
        string prefix = "0-";
        while (string.IsNullOrEmpty(fullNameWithoutRoot) || File.Exists(Path.Combine(AbsoluteFileSavePath, fullNameWithoutRoot)))
        {
            if (!string.IsNullOrEmpty(fullNameWithoutRoot))
            {//处理重复的文件名
                if (reFileName.IsMatch(filename))
                {
                    int num = int.Parse(reFileName.Match(filename).Result("$1")) + 1;
                    filename = num.ToString() + filename.Substring(1);
                }
                else
                {
                    filename = prefix + filename;
                }
            }
            fullNameWithoutRoot = extDir + todayDir + filename;
        }

        return fullNameWithoutRoot;
    }

    /// <summary>
    /// json转义
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    string ToJsonString(string str)
    {
        if (string.IsNullOrEmpty(str))
            return string.Empty;

        str = str.Replace("\\", "\\\\");
        str = str.Replace("/", "\\/");
        str = str.Replace("'", "\\'");
        return str;
    }

    /// <summary>
    /// 输出错误
    /// </summary>
    /// <param name="response"></param>
    /// <param name="error"></param>
    void WriteError(HttpResponse response, string error)
    {
        response.Write("{'err':'" + ToJsonString(error) + "','msg':''}");
    }

    /// <summary>
    /// 输出消息
    /// </summary>
    /// <param name="response"></param>
    /// <param name="message"></param>
    void WriteMessage(HttpResponse response, string message)
    {
        response.Write("{'err':'','msg':" + message + "}");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    /// <summary>
    /// 图片处理
    /// </summary>
    public abstract class ImageUtil
    {
        /// <summary>
        /// 应用图片水印
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="waterImage">水印图片</param>
        /// <returns></returns>
        public static Image ApplyImageWatermark(Image image, Image waterImage)
        {
            int width = waterImage.Width, height = waterImage.Height;
            if (width >= image.Width || height >= image.Height)
            {
                return image;
            }
            float alphaScaling = 1f;//透明度
            byte[] bytes = GetBytes(waterImage);
            Rectangle rect = GetRectangleInsideImage(image, width, height);
            using (Graphics graphics = Graphics.FromImage(image))
            {
                using (MemoryStream stream = new MemoryStream(bytes))
                {
                    using (Image image2 = Image.FromStream(stream))
                    {
                        AddWatermark(graphics, image2, rect, alphaScaling);
                    }
                    return image;
                }
            }
        }

        /// <summary>
        /// 应用文字水印
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="waterText">水印文字</param>
        /// <param name="fontFamily">字体</param>
        /// <param name="fontColor">字体颜色</param>
        /// <param name="fontSize">字体大小</param>
        /// <param name="fontstyle"></param>
        /// <returns></returns>
        private static Image ApplyTextWatermark(Image image, string waterText, string fontFamily, Color fontColor, int fontSize, FontStyle fontstyle)
        {
            int num;
            SizeF ef;
            bool preserveResolution = false;
            using (Bitmap bitmap = GetBitmapFromImage(image, image.Width, image.Height, preserveResolution))
            {
                using (Graphics graphics = Graphics.FromImage(bitmap))
                {
                    num = GetBestFontSize(image, graphics, fontFamily, fontSize, fontstyle, out ef);
                }
            }
            int width = (int)Math.Ceiling((double)ef.Width);
            int height = (int)Math.Ceiling((double)ef.Height);
            Rectangle rect = GetRectangleInsideImage(image, width, height);
            using (Bitmap bitmap2 = new Bitmap(width, height))
            {
                using (Graphics graphics2 = Graphics.FromImage(bitmap2))
                {
                    using (Font font = new Font(fontFamily, (float)num, fontstyle))
                    {
                        using (Brush brush = new SolidBrush(fontColor))
                        {
                            graphics2.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                            using (Brush brush2 = new SolidBrush(Color.AntiqueWhite))
                            {
                                graphics2.DrawString(waterText, font, brush2, new PointF(-1f, -1f));
                                //graphics2.DrawString(waterText, font, brush2, new PointF(.5f, .5f));
                            }
                            graphics2.DrawString(waterText, font, brush, new PointF(0f, 0f));
                        }
                    }
                }
                using (Graphics graphics3 = Graphics.FromImage(image))
                {
                    AddWatermark(graphics3, bitmap2, rect, 1f);
                }
            }
            return image;
        }

        private static int GetBestFontSize(Image image, Graphics graphics, string fontFamily, int fontSize, FontStyle fontStyle, out SizeF textArea)
        {
            SizeF layoutArea = new SizeF((float)(image.Width), (float)(image.Height));
            textArea = layoutArea;
            using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.MeasureTrailingSpaces))
            {
                for (int i = fontSize; i >= 2; i--)
                {
                    int charactersFitted = 0;
                    int linesFilled = 0;
                    using (Font font = new Font(fontFamily, (float)i, fontStyle))
                    {
                        textArea = graphics.MeasureString(watermarkTextorImage, font, layoutArea, format, out charactersFitted, out linesFilled);
                    }
                    if (((charactersFitted >= watermarkTextorImage.Length) && (textArea.Width <= layoutArea.Width)) && (textArea.Height <= layoutArea.Height))
                    {
                        return i;
                    }
                    fontSize = i;
                }
            }
            return fontSize;
        }

        private static byte[] GetBytes(Image image)
        {
            using (image)
            {
                using (MemoryStream stream2 = new MemoryStream())
                {
                    image.Save(stream2, image.RawFormat);
                    return stream2.ToArray();
                }
            }
        }

        private static Rectangle GetRectangleInsideImage(Image image, int width, int height)
        {
            int padding;//水平位置
            int num2;//垂直位置


            //padding = 0;//左
            padding = (image.Width - width);//右
            //padding = (image.Width - width) / 2;//中

            //num2 = 0;//上
            num2 = (image.Height - height);//下
            //num2 = (image.Height - height) / 2;//中
            return new Rectangle(padding, num2, width, height);
        }

        #region 添加水印
        public static void AddWatermark(Graphics targetGraphics, Image watermark, Rectangle rect, float alphaScaling)
        {
            ColorMatrix newColorMatrix = new ColorMatrix(GetScalingMatrix(alphaScaling));
            using (ImageAttributes attributes = new ImageAttributes())
            {
                attributes.SetColorMatrix(newColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Default);
                targetGraphics.DrawImage(watermark, rect, 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, attributes);
            }
        }

        private static float[][] GetScalingMatrix(float alphaScaling)
        {
            if (alphaScaling == 1f)
            {
                if (IdentityScalingMatrix == null)
                    IdentityScalingMatrix = GetScalingMatrixInternal(1f);
                return IdentityScalingMatrix;
            }
            return GetScalingMatrixInternal(alphaScaling);
        }

        private static float[][] GetScalingMatrixInternal(float alphaScaling)
        {
            float[][] numArray = new float[5][];
            float[] numArray2 = new float[5];
            numArray2[0] = 1f;
            numArray[0] = numArray2;
            float[] numArray3 = new float[5];
            numArray3[1] = 1f;
            numArray[1] = numArray3;
            float[] numArray4 = new float[5];
            numArray4[2] = 1f;
            numArray[2] = numArray4;
            float[] numArray5 = new float[5];
            numArray5[3] = alphaScaling;
            numArray[3] = numArray5;
            float[] numArray6 = new float[5];
            numArray6[4] = 1f;
            numArray[4] = numArray6;
            return numArray;
        }

        private static float[][] IdentityScalingMatrix;
        #endregion

        /// <summary>
        /// 生成缩略图
        /// </summary>
        /// <param name="content"></param>
        /// <param name="filename"></param>
        /// <param name="useWatermark">是否为图片添加水印</param>
        public static void ThumbnailImage(byte[] content, string filename, bool useWatermark)
        {
            if (filename.Contains("image/"))
            {
                if (useWatermark)
                {
                    using (Image img0 = Image.FromStream(new MemoryStream(content)))
                    {
                        using (Image img2 = GetBitmapFromImage(img0, img0.Width, img0.Height, true))
                        {
                            Image img1 = null;
                            if (isTextWatermark)
                            {
                                img1 = ApplyTextWatermark(img2, watermarkTextorImage, waterFont, waterColor, waterFontSize, waterFontStyle);
                            }
                            else
                                img1 = ApplyImageWatermark(img2, Image.FromFile(watermarkTextorImage));
                            using (img1)
                            {
                                SaveImage(img1, filename);
                            }
                        }
                    }
                }

                int tWidth = thumbWidth, tHeight = thumbHeight;
                string thumbFileName = Path.GetDirectoryName(filename) + "/thumb_" + Path.GetFileName(filename);
                using (Image image = Image.FromStream(new MemoryStream(content)))
                {
                    double num3 = (tHeight * 100.0) / ((double)image.Height);
                    double num4 = (tWidth * 100.0) / ((double)image.Width);
                    if (num3 > num4)
                    {
                        tHeight = (int)Math.Round((double)((num4 * image.Height) / 100.0));
                    }
                    else if (num3 < num4)
                    {
                        tWidth = (int)Math.Round((double)((num3 * image.Width) / 100.0));
                    }
                    if (tHeight > image.Height)
                    {
                        tHeight = image.Height;
                    }
                    if (tWidth > image.Width)
                    {
                        tWidth = image.Width;
                    }

                    using (Image thumbImage = GetBitmapFromImage(image, tWidth, tHeight, true))
                    {
                        if (useWatermark)
                        {
                            Image timg = null;
                            if (isTextWatermark)
                                timg = ApplyTextWatermark(thumbImage, watermarkTextorImage, waterFont, waterColor, waterFontSize, waterFontStyle);
                            else
                                timg = ApplyImageWatermark(thumbImage, Image.FromFile(watermarkTextorImage));
                            using (timg)
                            {
                                SaveImage(timg, thumbFileName);
                            }
                        }
                        else
                            SaveImage(thumbImage, thumbFileName);
                    }
                }
            }
        }

        /// <summary>
        /// 图片存为jpg格式
        /// </summary>
        /// <param name="img"></param>
        /// <param name="file"></param>
        private static void SaveImage(Image img, string file)
        {
            //file = DateTime.Now.ToString("yyMMddHHmmssffff") + Path.GetExtension(file);
            //HttpContext.Current.Response.Write("<script>alert('"+file+"')</script>");
            if (file.EndsWith(".jpg") || file.EndsWith(".jpeg"))
            {//jpeg格式
                try
                {
                    using (EncoderParameters parms = new EncoderParameters(1))
                    {
                        parms.Param[0] = new EncoderParameter(Encoder.Compression, 40);

                        img.Save(file, jpegCodec, parms);
                    }
                }
                catch
                {
                    img.Save(file);
                }
            }
            else
                img.Save(file);
        }

        private static ImageCodecInfo jpegCodec = GetImageEncoder("JPEG");

        /// <summary>
        /// Obtain an image encoder suitable for a specific graphics format.
        /// </summary>
        /// <param name="imageType">One of: BMP, JPEG, GIF, TIFF, PNG.</param>
        /// <returns>An ImageCodecInfo corresponding with the type requested,
        /// or null if the type was not found.</returns>
        private static ImageCodecInfo GetImageEncoder(string imageType)
        {
            imageType = imageType.ToUpperInvariant();

            foreach (ImageCodecInfo info in ImageCodecInfo.GetImageEncoders())
            {
                if (info.FormatDescription == imageType)
                {
                    return info;
                }
            }

            return null;
        }

        private static Bitmap GetBitmapFromImage(Image image, int width, int height, bool preserveResolution)
        {
            bool flag = (((image.PixelFormat == PixelFormat.Format1bppIndexed) || (image.PixelFormat == PixelFormat.Format4bppIndexed)) || (image.PixelFormat == PixelFormat.Format8bppIndexed)) || (image.PixelFormat == PixelFormat.Indexed);
            Bitmap bitmap = flag ? new Bitmap(width, height) : new Bitmap(width, height, image.PixelFormat);
            if (preserveResolution)
            {
                bitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);
            }
            else
            {
                bitmap.SetResolution(96f, 96f);
            }
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                if (flag)
                {
                    graphics.FillRectangle(Brushes.White, 0, 0, width, height);
                }
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.DrawImage(image, 0, 0, width, height);
            }
            return bitmap;
        }
    }
}